﻿using System;
using System.Collections.Generic;
using System.Text;

namespace AMS.DataAccess.Common
{
    /// <summary>
    /// 
    /// </summary>
    public enum SortDirection
    {
        ASC = 0,
        DESC = 1
    }

    /// <summary>
    /// 
    /// </summary>
    public class SqlInfo
    {
        private SortDirection pkSort = SortDirection.DESC;
        /// <summary>
        /// 查询的SQL语句，不能包括ORDER BY表达式
        /// </summary>
        public string BaseSql { get; set; }

        /// <summary>
        /// 排序表达式
        /// </summary>
        public string SoreExpression { get; set; }

        /// <summary>
        /// 查询语句中一个可以充当主键的字段
        /// </summary>
        public string PKField { get; set; }

        /// <summary>
        /// Default value: DESC
        /// </summary>
        public SortDirection PKSort
        {
            get { return pkSort; }
            set { pkSort = value; }
        }
    }

    /// <summary>
    /// 分页信息
    /// </summary>
    public class PagerInfo
    {
        /// <summary>
        /// 
        /// </summary>
        public PagerInfo()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        public PagerInfo(int pageIndex, int pageSize)
        {
            PageIndex = pageIndex;
            PageSize = pageSize;
        }

        /// <summary>
        /// 
        /// </summary>
        public int PageIndex { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int PageSize { get; set; }
    }

    /// <summary>
    /// 
    /// </summary>
    public class PagedSqlInfo
    {
        /// <summary>
        /// 
        /// </summary>
        public string PagedSql { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string TotalCountSql { get; set; }
    }

    /// <summary>
    /// 
    /// </summary>
    public class PagerWrapper
    {
        private static readonly string selectSqlTp =
@"select * from( select _r.*, row_number() over([pk_orderby]) as __row__ from (
[basesql])_r )_t where _t.__row__ >= [low] and _t.__row__ <= [high]";

        /// <summary>
        /// 
        /// </summary>
        public static int FirstPageIndex = 0;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sqlInfo"></param>
        /// <param name="pagerInfo"></param>
        /// <returns></returns>
        public static PagedSqlInfo WrapSql(SqlInfo sqlInfo, PagerInfo pagerInfo)
        {
            PagedSqlInfo pagedSql = new PagedSqlInfo();
            WrapSql(sqlInfo, pagerInfo, ref pagedSql);
            return pagedSql;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sqlInfo"></param>
        /// <param name="pagerInfo"></param>
        /// <param name="pagedSql"></param>
        public static void WrapSql(SqlInfo sqlInfo, PagerInfo pagerInfo, ref PagedSqlInfo pagedSql)
        {
            if (pagedSql == null)
            {
                throw new ArgumentNullException("pagedSql cannot be null");
            }

            if (pagerInfo.PageIndex == 0 && FirstPageIndex == 1)
            {
                throw new ArgumentException("The first page index of pagerInfo cannot not be less than the default first page index.");
            }

            StringBuilder sql = new StringBuilder();
            if (pagerInfo.PageIndex == FirstPageIndex)
            {
                sql.Append("SELECT TOP ");
                sql.Append(pagerInfo.PageSize.ToString());
                sql.AppendLine(" * FROM (");
                sql.Append(sqlInfo.BaseSql);
                sql.Append(")_t");

                pagedSql.PagedSql = sql.ToString();
            }
            else
            {
                sql.AppendLine(selectSqlTp);
                sql.Replace("[pk_orderby]", "ORDER BY " + sqlInfo.PKField + SortDirectionToString(sqlInfo.PKSort));
                sql.Replace("[basesql]", sqlInfo.BaseSql);
                sql.Replace("[low]", GetLowerBound(pagerInfo));
                sql.Replace("[high]", GetHigherBound(pagerInfo));
                if (!string.IsNullOrEmpty( sqlInfo.SoreExpression))
                {
                    sql.Append("    ORDER BY ");
                    sql.AppendLine(sqlInfo.SoreExpression);
                }

                pagedSql.PagedSql = sql.ToString();
            }

            pagedSql.TotalCountSql = string.Format("SELECT COUNT(1) FROM ({0})_t", sqlInfo.BaseSql);
        }

        private static string SortDirectionToString(SortDirection dir)
        {
            return (dir == SortDirection.ASC ? " ASC" : " DESC");
        }

        private static string GetLowerBound(PagerInfo pager)
        {
            if (FirstPageIndex == 0)
            {
                return (pager.PageIndex * pager.PageSize).ToString();
            }
            else
            {
                return (pager.PageIndex * pager.PageSize - pager.PageSize).ToString();
            }
        }

        private static string GetHigherBound(PagerInfo pager)
        {
            if (FirstPageIndex == 0)
            {
                return (pager.PageIndex * pager.PageSize + pager.PageSize).ToString();
            }
            else
            {
                return (pager.PageIndex * pager.PageSize).ToString();
            }
        }
    }
}
